package com.blog4j.server.modules.sms.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.blog4j.api.client.FeignSystem;
import com.blog4j.api.vo.SystemBaseConfigVo;
import com.blog4j.common.constants.CacheConstants;
import com.blog4j.common.enums.ErrorEnum;
import com.blog4j.common.enums.PhoneCodeEnum;
import com.blog4j.common.enums.YesOrNoEnum;
import com.blog4j.common.exception.Blog4jException;
import com.blog4j.common.utils.RedisUtil;
import com.blog4j.server.modules.sms.properties.SmsProperties;
import com.blog4j.server.modules.sms.service.SmsService;
import com.blog4j.server.modules.sms.utils.SmsUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.util.Objects;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2024/7/27 18:02
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Slf4j
public class SmsServiceImpl implements SmsService {
    private final SmsProperties smsProperties;
    private final RedisUtil redisUtil;
    private final FeignSystem feignSystem;
    private final ObjectMapper objectMapper;

    /**
     * 获取短信验证码
     *
     * @param phone 手机号码
     * @return 短信验证码
     */
    @Override
    public String getPhoneCode(String phone, String type) {
        SystemBaseConfigVo systemBaseConfig = this.getSystemBaseConfig();
        if (Objects.equals(systemBaseConfig.getOpenSms(), YesOrNoEnum.NO.getCode())) {
            throw new Blog4jException(ErrorEnum.NOT_ALLOW_SMS_ERROR);
        }

        String cacheKey = StringUtils.equals(type, PhoneCodeEnum.LOGIN.getType()) ?
                CacheConstants.PHONE_CODE_KEY + phone :  CacheConstants.VALID_PHONE_CODE_KEY + phone;

        Object cacheCode = redisUtil.get(cacheKey);
        if (Objects.nonNull(cacheCode)) {
            redisUtil.del(cacheKey);
        }
        String code = SmsUtil.createMsmCode();
        this.sendSmsCode(phone, code);
        // 存到redis
        redisUtil.set(cacheKey, code, CacheConstants.PHONE_CODE_LOGIN_EXPIRE_TIME);
        return code;
    }

    private void sendSmsCode(String phone, String code) {
        String url = smsProperties.getSmsUrl();
        String token = smsProperties.getSmsToken();
        String username = smsProperties.getUsername();
        String password = smsProperties.getPassword();
        String templateId = smsProperties.getTemplateId();
        long timeMillis = System.currentTimeMillis();
        String beforeSign;
        String postData;
        try {
            beforeSign = "action=sendtemplate&username=" + username + "&password=" + SmsUtil.getMD5String(password)
                    + "&token=" + token + "&timestamp=" + timeMillis;
            postData = "action=sendtemplate&username=" + username + "&password=" + SmsUtil.getMD5String(password)
                    + "&token=" + token + "&templateid=" + templateId + "&param=" + phone + "|" + code + "&rece=json&timestamp="
                    + timeMillis + "&sign=" + SmsUtil.getMD5String(beforeSign);
        } catch(NoSuchAlgorithmException noSuchAlgorithmException) {
            log.error("SmsNoSuchAlgorithmException ...");
            throw new Blog4jException(ErrorEnum.SYSTEM_ERROR);
        }
        SmsUtil.sendPost(url, postData);
    }

    private SystemBaseConfigVo getSystemBaseConfig()  {
        Object val = redisUtil.get(CacheConstants.SYSTEM_BASE_CONFIG_KEY);
        if (Objects.isNull(val)) {
            return feignSystem.getBaseSystemConfig();
        }

        try {
            JSONArray jsonArray = JSON.parseArray((String) val);
            JSONObject jsonObject = JSON.parseObject(objectMapper.writeValueAsString(jsonArray.get(1)));
            return JSON.toJavaObject(jsonObject, SystemBaseConfigVo.class);
        } catch (Exception exception) {
            throw new Blog4jException(ErrorEnum.PARSE_ERROR);
        }
    }
}
